home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d8 / pdriver5.arc / 3C501.ASM next >
Assembly Source File  |  1989-12-17  |  14KB  |  621 lines

  1. version    equ    0
  2.  
  3.     include    defs.asm
  4.  
  5. ;Ported from Phil Karn's ec.c, a C-language driver for the 3COM 3C501
  6. ;by Russell Nelson.  Any bugs are due to Russell Nelson.
  7. ;*  Updated to version 1.08 Feb. 17, 1989.
  8.  
  9. ;  Copyright, 1988, 1989, Russell Nelson
  10.  
  11. ;   This program is free software; you can redistribute it and/or modify
  12. ;   it under the terms of the GNU General Public License as published by
  13. ;   the Free Software Foundation, version 1.
  14. ;
  15. ;   This program is distributed in the hope that it will be useful,
  16. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. ;   GNU General Public License for more details.
  19. ;
  20. ;   You should have received a copy of the GNU General Public License
  21. ;   along with this program; if not, write to the Free Software
  22. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23.  
  24. code    segment    byte public
  25.     assume    cs:code, ds:code
  26.  
  27. ;The various IE command registers
  28. EDLC_ADDR    equ    00h    ;EDLC station address, 6 bytes
  29. EDLC_RCV    equ    06h    ;EDLC receive csr
  30. EDLC_XMT    equ    07h    ;EDLC transmit csr
  31. IE_GP        equ    08h    ;GP pointer
  32. IE_RP        equ    0ah    ;Receive buffer pointer
  33. IE_SAPROM    equ    0ch    ;window on station addr prom
  34. IE_CSR        equ    0eh    ;IE command/status
  35. IE_BFR        equ    0fh    ;window on packet buffer
  36.  
  37. ;Bits in EDLC_RCV, interrupt enable on write, status when read
  38. EDLC_NONE    equ    000h    ;match mode in bits 5-6, write only
  39. EDLC_ALL    equ    040h    ;promiscuous receive, write only
  40. EDLC_BROAD    equ    080h    ;station address plus broadcast
  41. EDLC_MULTI    equ    0c0h    ;station address plus multicast
  42.  
  43. EDLC_STALE    equ    80h    ;receive CSR status previously read
  44. EDLC_GOOD    equ    20h    ;well formed packets only
  45. EDLC_ANY    equ    10h    ;any packet, even those with errors
  46. EDLC_SHORT    equ    08h    ;short frame
  47. EDLC_DRIBBLE    equ    04h    ;dribble error
  48. EDLC_FCS    equ    02h    ;CRC error
  49. EDLC_OVER    equ    01h    ;data overflow
  50.  
  51. EDLC_RERROR    equ    EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
  52. EDLC_RMASK    equ    EDLC_GOOD or EDLC_ANY or EDLC_RERROR
  53.  
  54. ;bits in EDLC_XMT, interrupt enable on write, status when read
  55. EDLC_IDLE    equ    08h    ;transmit idle
  56. EDLC_16        equ    04h    ;packet experienced 16 collisions
  57. EDLC_JAM    equ    02h    ;packet experienced a collision
  58. EDLC_UNDER    equ    01h    ;data underflow
  59.  
  60. ;bits in IE_CSR
  61. IE_RESET    equ    80h    ;reset the controller (wo)
  62. IE_XMTBSY    equ    80h    ;Transmitter busy (ro)
  63. IE_RIDE        equ    40h    ;request interrupt/DMA enable (rw)
  64. IE_DMA        equ    20h    ;DMA request (rw)
  65. IE_EDMA        equ    10h    ;DMA done (ro)
  66.  
  67. IE_BUFCTL    equ    0ch    ;mask for buffer control field (rw)
  68. IE_LOOP        equ    0ch    ;2 bit field in bits 2,3, loopback
  69. IE_RCVEDLC    equ    08h    ;gives buffer to receiver
  70. IE_XMTEDLC    equ    04h    ;gives buffer to transmit
  71. IE_SYSBFR    equ    00h    ;gives buffer to processor
  72.  
  73. IE_CRC        equ    01h    ;causes CRC error on transmit (wo)
  74. IE_RCVBSY    equ    01h    ;receive in progress (ro)
  75.  
  76. BFRSIZ        equ    2048    ;number of bytes in a buffer
  77.  
  78.     public    int_no
  79. int_no        db    3,0,0,0        ; interrupt number.
  80. io_addr        dw    0300h,0        ; I/O address for card (jumpers)
  81.  
  82.     public    driver_class, driver_type, driver_name
  83. driver_class    db    1        ;from the packet spec
  84. driver_type    db    1        ;from the packet spec
  85. driver_name    db    '3C501',0    ;name of the driver.
  86.  
  87.     public    rcv_modes
  88. rcv_modes    dw    4        ;number of receive modes in our table.
  89.         dw    0,0,0,rcv_mode_3
  90.  
  91. ipkt_size    dw    ?
  92. opkt_size    dw    ?
  93.  
  94. is_186        db    0        ;=0 if 808[68], =1 if 80[123]86.
  95. our_type    dw    ?
  96.  
  97.     public    send_pkt
  98. send_pkt:
  99. ;enter with ds:si -> packet, cx = packet length.
  100. ;exit with nc if ok, or else cy if error, dh set to error number.
  101.     assume    ds:nothing
  102.     cmp    cx,RUNT        ; minimum length for Ether
  103.     jae    oklen
  104.     mov    cx,RUNT        ; make sure size at least RUNT
  105. oklen:
  106.     inc    cx            ;round size up to next even number.
  107.     and    cx,not 1
  108.  
  109. ;Wait for transmitter ready, if necessary. IE_XMTBSY is valid
  110. ;only in the transmit mode, hence the initial check.
  111.  
  112.     loadport
  113.     setport    IE_CSR
  114.     in    al,dx
  115.     and    al,IE_BUFCTL
  116.     cmp    al,IE_XMTEDLC
  117.     jne    send_pkt_2
  118.  
  119.     mov    bx,20000        ;try this many times.
  120. send_pkt_3:
  121.     in    al,dx            ;if not busy, exit.
  122.     and    al,IE_XMTBSY
  123.     je    send_pkt_2
  124.     dec    bx
  125.     jne    send_pkt_3
  126.     mov    dh,CANT_SEND        ;timed out, can't send.
  127.     stc
  128.     ret
  129. send_pkt_2:
  130.  
  131. ;Get control of the board buffer and disable receiver
  132.     mov    al,IE_RIDE or IE_SYSBFR
  133.     setport    IE_CSR
  134.     out    dx,al
  135.  
  136. ;Point GP at beginning of packet
  137.     mov    ax,BFRSIZ
  138.     sub    ax,cx
  139.     setport    IE_GP
  140.     out    dx,ax
  141.  
  142.     setport    IE_BFR
  143.  
  144.     mov    opkt_size,cx    ; opkt_size = cx;
  145.     cmp    is_186,0    ; Can we use rep outsb?
  146.     je    out86        ; no - have to do it slowly.
  147.     rep    outsb
  148.     jmp    short ocnteven
  149. out86:
  150.     test    si,1        ; (buf & 1) ?
  151.     jz    obufeven    ; no
  152.     lodsb            ; al = *si++;
  153.     out    dx,al        ; out(dx,al);
  154.     dec    cx        ; cx--;
  155. obufeven:
  156.     mov    di,cx        ; save for later test
  157.     shr    cx,1        ; cx = cnt >> 1; (convert to word count)
  158. ; Do the bulk of the buffer, a word at a time
  159.     jcxz    onobuf        ; if(cx != 0){
  160. xb:    lodsw            ; do { ax = *si++; (si is word pointer)
  161.     out    dx,al        ; out(dx,lowbyte(ax));
  162.     mov    al,ah
  163.     out    dx,al        ; out(dx,hibyte(ax));
  164.     loop    xb        ; } while(--cx != 0); }
  165. ; now check for odd trailing byte
  166. onobuf:    shr    di,1        ; if (di & 1)
  167.     jnc    ocnteven
  168.     lodsb            ;   out(dx,*si++);
  169.     out    dx,al
  170. ocnteven:
  171.  
  172. ;Start transmitter
  173. ;Point GP at beginning of packet
  174.     mov    ax,BFRSIZ
  175.     sub    ax,opkt_size
  176.     setport    IE_GP
  177.     out    dx,ax
  178.  
  179.     mov    al,IE_RIDE or IE_XMTEDLC
  180.     setport    IE_CSR
  181.     out    dx,al
  182.  
  183.     clc
  184.     ret
  185.  
  186.  
  187.     public    get_address
  188. get_address:
  189. ;get the address of the interface.
  190. ;enter with es:di -> place to get the address, cx = size of address buffer.
  191. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  192.     assume    ds:code
  193.     cmp    cx,EADDR_LEN        ;make sure that we have enough room.
  194.     jb    get_address_2
  195.     mov    cx,EADDR_LEN
  196.     xor    bx,bx
  197. get_address_1:
  198.     mov    ax,bx
  199.     loadport
  200.     setport    IE_GP
  201.     out    dx,ax
  202.  
  203.     setport    IE_SAPROM
  204.     in    al,dx
  205.     stosb
  206.     inc    bx
  207.     loop    get_address_1
  208.  
  209.     mov    cx,EADDR_LEN
  210.     clc
  211.     ret
  212. get_address_2:
  213.     stc
  214.     ret
  215.  
  216.  
  217. ;Set Ethernet address on controller
  218.     public    set_address
  219. set_address:
  220.     assume    ds:nothing
  221. ;enter with ds:si -> Ethernet address, CX = length of address.
  222. ;exit with nc if okay, or cy, dh=error if any errors.
  223. ;
  224.     cmp    cx,EADDR_LEN        ;ensure that their address is okay.
  225.     je    set_address_4
  226.     mov    dh,BAD_ADDRESS
  227.     stc
  228.     jmp    short set_address_done
  229. set_address_4:
  230.  
  231.     loadport
  232.     setport    EDLC_ADDR
  233. set_address_1:
  234.     lodsb
  235.     out    dx,al
  236.     inc    dx
  237.     loop    set_address_1
  238. set_address_okay:
  239.     mov    cx,EADDR_LEN        ;return their address length.
  240.     clc
  241. set_address_done:
  242.     push    cs
  243.     pop    ds
  244.     assume    ds:code
  245.     ret
  246.  
  247.  
  248. terminate:
  249. ;Pulse IE_RESET
  250.     mov    al,IE_RESET
  251.     loadport
  252.     setport    IE_CSR
  253.     out    dx,al
  254.     mov    al,0
  255.     out    dx,al
  256.  
  257.     ret
  258.  
  259.  
  260. rcv_mode_3:
  261. ;receive mode 3 is the only one we support, so we don't have to do anything.
  262.     ret
  263.  
  264.  
  265.     public    set_multicast_list
  266. set_multicast_list:
  267. ;enter with es:di ->list of multicast addresses, cx = number of bytes.
  268. ;return nc if we set all of them, or cy,dh=error if we didn't.
  269.     mov    dh,NO_MULTICAST
  270.     stc
  271.     ret
  272.  
  273.  
  274.     public    get_multicast_list
  275. get_multicast_list:
  276. ;return with nc, es:di ->list of multicast addresses, cx = number of bytes.
  277. ;return cy, NO_ERROR if we don't remember all of the addresses ourselves.
  278. ;return cy, NO_MULTICAST if we don't implement multicast.
  279.     mov    dh,NO_MULTICAST
  280.     stc
  281.     ret
  282.  
  283.  
  284.     public    reset_interface
  285. reset_interface:
  286. ;reset the interface.
  287. ;we don't do anything.
  288.     ret
  289.  
  290.  
  291. ;called when we want to determine what to do with a received packet.
  292. ;enter with cx = packet length, es:di -> packet type.
  293.     extrn    recv_find: near
  294.  
  295. ;called after we have copied the packet into the buffer.
  296. ;enter with ds:si ->the packet, cx = length of the packet.
  297.     extrn    recv_copy: near
  298.  
  299.     extrn    count_in_err: near
  300.     extrn    count_out_err: near
  301.  
  302.     public    recv
  303. recv:
  304. ;called from the recv isr.  All registers have been saved, and ds=cs.
  305. ;Upon exit, the interrupt will be acknowledged.
  306.     assume    ds:code
  307.  
  308. ;Check for transmit jam
  309.  
  310.     loadport
  311.     setport    IE_CSR
  312.     in    al,dx
  313.     and    al,IE_XMTBSY
  314.     jne    recv_isr_1
  315.  
  316.     setport    EDLC_XMT
  317.     in    al,dx
  318.     test    al,EDLC_16
  319.     je    recv_isr_2
  320. ;ecp->estats.jam16++;
  321.     call    rcv_fixup
  322.     jmp    short     recv_isr_3
  323. recv_isr_2:
  324.     test    al,EDLC_JAM
  325.     je    recv_isr_3
  326. ;Crank counter back to beginning and restart transmit
  327. ;ecp->estats.jam++;
  328.     mov    al,IE_RIDE or IE_SYSBFR
  329.     setport    IE_CSR
  330.     out    dx,al
  331.  
  332.     mov    ax,BFRSIZ
  333.     sub    ax,opkt_size
  334.     setport    IE_GP
  335.     out    dx,ax
  336.  
  337.     mov    al,IE_RIDE or IE_XMTEDLC
  338.     setport    IE_CSR
  339.     out    dx,al
  340.  
  341. recv_isr_3:
  342.  
  343. recv_isr_1:
  344.     loadport
  345.     setport    EDLC_RCV
  346.     in    al,dx
  347.     test    al,EDLC_STALE
  348.     jne    recv_isr_4_j_1
  349.     test    al,EDLC_OVER
  350.     je    recv_isr_5
  351. ;ecp->estats.over++;
  352.     call    rcv_fixup
  353.     jmp    recv_isr_1
  354. recv_isr_5:
  355.     test    al,EDLC_SHORT or EDLC_FCS or EDLC_DRIBBLE
  356.     je    recv_isr_6
  357. ;ecp->estats.bad++;
  358.     call    rcv_fixup
  359.     jmp    recv_isr_1
  360. recv_isr_4_j_1:
  361.     jmp    recv_isr_4
  362. recv_isr_6:
  363.     test    al,EDLC_ANY
  364.     je    recv_isr_4_j_1
  365. ;Get control of the buffer
  366.     mov    al,IE_RIDE or IE_SYSBFR
  367.     setport    IE_CSR
  368.     out    dx,al
  369.  
  370.     setport    IE_RP
  371.     in    ax,dx            ;get the size.
  372.     mov    ipkt_size,ax
  373.     cmp    ax,RUNT            ;less than RUNT?
  374.     jb    recv_isr_7        ;yes.
  375.     cmp    ax,GIANT        ;greater than GIANT?
  376.     jbe    recv_isr_8        ;no.
  377. recv_isr_7:
  378.     call    count_in_err
  379. ;ecp->estats.bad++;
  380.     jmp    recv_isr_9
  381. recv_isr_8:
  382. ;Put it on the receive queue
  383.  
  384.     mov    ax,EADDR_LEN+EADDR_LEN    ;seek to the type word.
  385.     setport    IE_GP
  386.     out    dx,ax
  387.  
  388.     setport    IE_BFR
  389.     in    al,dx            ;read the type word out of the board.
  390.     mov    ah,al
  391.     in    al,dx
  392.     xchg    al,ah            ;should be in network byte order.
  393.     mov    our_type,ax
  394.  
  395.     mov    ax,ds            ;look up our type.
  396.     mov    es,ax
  397.     mov    di,offset our_type
  398.     mov    cx,ipkt_size
  399.     call    recv_find
  400.  
  401.     mov    ax,es            ;is this pointer null?
  402.     or    ax,di
  403.     je    recv_isr_9        ;yes - just free the frame.
  404.  
  405.     push    es            ;remember where the buffer pointer is.
  406.     push    di
  407.  
  408.     xor    ax,ax            ;seek to the beginning again.
  409.     loadport
  410.     setport    IE_GP
  411.     out    dx,ax
  412.  
  413.     mov    cx,ipkt_size
  414.     setport    IE_BFR
  415.  
  416.     cmp    is_186,0    ; Can we use rep insb?
  417.     je    in86        ; no - have to do it slowly.
  418.     rep    insb
  419.     jmp    short icnteven
  420. in86:
  421. ; If buffer doesn't begin on a word boundary, get the first byte
  422.     test    di,1    ; if(buf & 1){
  423.     jz    ibufeven ;
  424.     in    al,dx    ; al = in(dx);
  425.     stosb        ; *di++ = al
  426.     dec    cx    ; cx--;
  427. ibufeven:
  428.     mov    si,cx    ; size = cx;
  429.     shr    cx,1    ; cx = cnt >> 1; (convert to word count)
  430. ; Do the bulk of the buffer, a word at a time
  431.     jcxz    inobuf    ; if(cx != 0){
  432. rb:    in    al,dx    ; do { al = in(dx);
  433.     mov    ah,al
  434.     in    al,dx    ; ah = in(dx);
  435.     xchg    al,ah
  436.     stosw        ; *si++ = ax; (di is word pointer)
  437.     loop    rb    ; } while(--cx != 0);
  438. ; now check for odd trailing byte
  439. inobuf:    shr    si,1
  440.     jnc    icnteven
  441.     in    al,dx
  442.     stosb        ; *di++ = al
  443. icnteven:
  444.  
  445.     pop    si
  446.     pop    ds
  447.     assume    ds:nothing
  448.     mov    cx,ipkt_size
  449.     call    recv_copy        ;tell them that we copied it.
  450.  
  451.     mov    ax,cs            ;restore our ds.
  452.     mov    ds,ax
  453.     assume    ds:code
  454.  
  455. recv_isr_9:
  456.     mov    al,IE_RIDE or IE_RCVEDLC
  457.     loadport
  458.     setport    IE_CSR
  459.     out    dx,al
  460.     xor    al,al
  461.     setport    IE_RP
  462.     out    dx,al
  463. recv_isr_4:
  464. ;Clear any spurious interrupts
  465.     loadport
  466.     setport    EDLC_RCV
  467.     in    al,dx
  468.  
  469.     setport    EDLC_XMT
  470.     in    al,dx
  471.  
  472.     ret
  473.  
  474.  
  475. rcv_fixup:
  476.     call    count_out_err
  477.  
  478.     mov    al,IE_RIDE or IE_SYSBFR
  479.     loadport
  480.     setport    IE_CSR
  481.     out    dx,al
  482.  
  483.     mov    al,IE_RIDE or IE_RCVEDLC
  484.     setport    IE_CSR
  485.     out    dx,al
  486.  
  487.     mov    al,0
  488.     setport    IE_RP
  489.     out    dx,al
  490.  
  491.     ret
  492.  
  493.  
  494.     public    recv_exiting
  495. recv_exiting:
  496. ;called from the recv isr after interrupts have been acknowledged.
  497. ;Only ds and ax have been saved.
  498.     assume    ds:nothing
  499.     ret
  500.  
  501.  
  502. end_resident    label    byte
  503.  
  504.     public    usage_msg
  505. usage_msg    db    "usage: 3C501 <packet_int_no> <int_no> <io_addr>",CR,LF,'$'
  506.  
  507.     public    copyright_msg
  508. copyright_msg    db    "Packet driver for the 3COM 3C501, version ",'0'+majver,".",'0'+version,CR,LF
  509.         db    "Portions Copyright 1988 Phil Karn",CR,LF,'$'
  510.  
  511. using_186_msg    db    "Using 80[123]86 I/O instructions.",CR,LF,'$'
  512. no_3c501_msg    db    "No 3C501 found at that address.",CR,LF,'$'
  513. ether_bdcst    db    6 dup(-1)    ;ethernet broadcast address.
  514. our_address    db    6 dup(?)    ;temporarily hold our address
  515.  
  516. int_no_name    db    "Interrupt number ",'$'
  517. io_addr_name    db    "I/O port ",'$'
  518.  
  519.     extrn    set_recv_isr: near
  520.  
  521. ;enter with si -> argument string, di -> word to store.
  522. ;if there is no number, don't change the number.
  523.     extrn    get_number: near
  524.  
  525.     public    parse_args
  526. parse_args:
  527.     mov    di,offset int_no
  528.     mov    bx,offset int_no_name
  529.     call    get_number
  530.     mov    di,offset io_addr
  531.     mov    bx,offset io_addr_name
  532.     call    get_number
  533.     ret
  534.  
  535.  
  536. no_3c501_error:
  537.     mov    dx,offset no_3c501_msg
  538.     mov    ah,9
  539.     int    21h
  540.     stc
  541.     ret
  542.  
  543.  
  544.     public    etopen
  545. etopen:
  546. ;  Initialize the Ethernet board, set receive type.
  547. ;
  548. ;  check for correct EPROM location
  549. ;
  550. ;Pulse IE_RESET
  551.     mov    al,IE_RESET
  552.     loadport
  553.     setport    IE_CSR
  554.     out    dx,al
  555.  
  556. ;Determine the processor type.  The 8088 and 8086 will actually shift ax
  557. ;over by 33 bits, while the 80[123]86 use a shift count mod 32.
  558.     mov    cl,33
  559.     mov    ax,0ffffh
  560.     shl    ax,cl
  561.     jz    not_186
  562.     mov    is_186,1
  563.     mov    dx,offset using_186_msg
  564.     mov    ah,9
  565.     int    21h
  566. not_186:
  567.  
  568.     call    set_recv_isr
  569.  
  570.     push    ds
  571.     pop    es
  572.     mov    di,offset our_address
  573.     mov    cx,EADDR_LEN
  574.     call    get_address
  575.     mov    si,offset our_address
  576.     mov    cx,EADDR_LEN
  577.     call    set_address
  578.  
  579. ;See if there really is a 3c501 there.
  580.     mov    cx,EADDR_LEN
  581.     mov    si,offset our_address
  582.     mov    di,offset ether_bdcst
  583.     repe    cmpsb
  584.     jne    have_3c501        ;not broadcast address -- must be real.
  585.     jmp    no_3c501_error        ;not there -- no 3c501.
  586. have_3c501:
  587.  
  588. ;Enable DMA/interrupt request, gain control of buffer
  589.     mov    al,IE_RIDE or IE_SYSBFR
  590.     loadport
  591.     setport    IE_CSR
  592.     out    dx,al
  593.  
  594. ;Enable transmit interrupts
  595.     mov    al,EDLC_16 or EDLC_JAM
  596.     setport    EDLC_XMT
  597.     out    dx,al
  598.  
  599. ;Set up the receiver interrupts and flush status
  600.     mov    al,EDLC_MULTI or EDLC_GOOD or EDLC_ANY or EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
  601.     setport    EDLC_RCV
  602.     out    dx,al
  603.     in    al,dx            ;flush status.
  604.  
  605. ;Start receiver
  606.     mov    ax,0            ;Reset read pointer
  607.     setport    IE_RP
  608.     out    dx,ax
  609.     mov    al,IE_RIDE or IE_RCVEDLC
  610.     setport    IE_CSR
  611.     out    dx,al
  612.  
  613.     mov    dx,offset end_resident
  614.     clc
  615.     ret
  616.  
  617.  
  618. code    ends
  619.  
  620.     end
  621.